﻿// 针对能被proxy保存的数据
Ext.util.Stateful = Ext.extend(Ext.util.Observable, {

    editing: false,                 //全局属性 用来判断模型是否正在被编辑，只读
    dirty: false,                   //只读标志 - 如果该记录被修改，则设为true

    persistanceProperty: 'data',    //Stateful对象中用于持久保存数据的属性的名称

    constructor: function (config) {

        //Ext.util.Stateful对象必有data属性
        Ext.applyIf(this, {
            data: {}
        });

        this.modified = {}; // 被修改过的数据

        this[this.persistanceProperty] = {}; // 指定的持久数据对象

        Ext.util.Stateful.superclass.constructor.call(this, config);
    },

    //根据"field"参数获取data属性（data: {}）的"field"值
    get: function (field) {
        return this[this.persistanceProperty][field];
    },

    //Sets the given field to the given value, marks the instance as dirty
    //fieldName: String|Object -The field to set, or an object containing key/value pairs
    //value: Mixed -The value to set
    set: function (fieldName, value) {
        var fields = this.fields,//属性集合（model中的fields值，model类是从Stateful类中继承过来的）
            convertFields = [],
            field, key, i;

        // 如果是通过一个对象来批量设置属性
        if (arguments.length == 1 && Ext.isObject(fieldName)) {
            for (key in fieldName) {
                if (!fieldName.hasOwnProperty(key)) {
                    continue;
                }

                // 获取当前属性对象
                field = fields.get(key); //field是Ext.data.Field对象

                // 如果自定义了字段类型值封装函数（field.type里面的是Ext.data.Types对象提供的默认封装函数）
                if (field && field.convert !== field.type.convert) {
                    convertFields.push(key);
                    continue;
                }

                // 设置单一字段
                this.set(key, fieldName[key]);
            }

            // 遍历类型被转换的字段
            for (i = 0; i < convertFields.length; i++) {
                field = convertFields[i];
                this.set(field, fieldName[field]);
            }

        } else { // 单一属性

            // 如果有字段集
            if (fields) {
                field = fields.get(fieldName);

                // 找到字段，并且字段有自定义类型值封装函数（其实肯定有，field封装成Ext.data.Field对象的时候已经初始化convert方法）
                if (field && field.convert) {
                    value = field.convert(value, this); //将值转换成字段封装的值
                }
            }

            //this.persistanceProperty：Stateful对象中用于持久保存数据的属性的名称
            this[this.persistanceProperty][fieldName] = value;//设置新值

            this.dirty = true;//说明字段值有改变

            if (!this.editing) {//当前Ext.util.Stateful对象（model对象）不是正在被编辑（这个字段没意义，没有为true的情况）
                this.afterEdit(); //编辑结束的操作（就是一个调用store的afterEdit方法）
            }
        }
    },

    //获取一个对象，该对象里面只有被修改的属性
    getChanges: function () {
        var modified = this.modified, // 有变更的字段
            changes = {},
            field;

        for (field in modified) {
            if (modified.hasOwnProperty(field)) {
                changes[field] = this[this.persistanceProperty][field];
            }
        }

        return changes;
    },

    //如果传人的字段的是被修改的字段，则返回true
    //modified是状态的初始值，用于还原
    isModified: function (fieldName) {
        return !!(this.modified && this.modified.hasOwnProperty(fieldName));
    },

    // 将所有字段都设置为变更字段（保护现场）
    setDirty: function () {
        this.dirty = true;

        if (!this.modified) {
            this.modified = {};
        }

        this.fields.each(function (field) {
            this.modified[field.name] = this[this.persistanceProperty][field.name];
        }, this);
    },

    markDirty: function () {
        throw new Error("Stateful: markDirty has been deprecated. Please use setDirty.");
    },

    // 将变动值注入持久值中（恢复现场）
    reject: function (silent) {
        var modified = this.modified,
            field;

        // 遍历有变动的字段
        for (field in modified) {
            if (!modified.hasOwnProperty(field)) {
                continue;
            }
            if (typeof modified[field] != "function") {
                this[this.persistanceProperty][field] = modified[field]; // 将有变动的字段的值注入到持久值中
            }
        }

        // 清除变动标记
        this.dirty = false; 
        this.editing = false;
        delete this.modified;

        // 如果没有设置默默变动，则运行后续操作（主要是通知store）
        if (silent !== true) {
            this.afterReject();
        }
    },

    // 提交操作，主要是改变状态
    commit: function (silent) {
        this.dirty = false;
        this.editing = false;

        delete this.modified;

        if (silent !== true) {
            this.afterCommit();
        }
    },


    copy: function (newId) {
        return new this.constructor(Ext.apply({}, this[this.persistanceProperty]), newId || this.internalId);
    }
});